<template>
  <div ref="chart" :style="{height: height + 'px', width: width + 'px'}"></div>
</template>

<script>
import * as d3 from "d3";

export default {
  name: "ScatterPlot",
  props: ["data", "width", "height", "yuan", "fons"],
  watch: {
    width: "createChart",
    height: "createChart",
  },
  mounted() {
    this.createChart();
  },
  methods: {
    createChart() {
      const component = this;

      // 清空已有的图表内容
      d3.select(this.$refs.chart).selectAll("*").remove();

      const svg = d3
        .select(this.$refs.chart)
        .append("svg")
        .attr("width", this.width)
        .attr("height", this.height)
        .attr("viewBox", `0 0 ${this.width} ${this.height}`)
        .attr("preserveAspectRatio", "xMidYMid meet");

      // 力模拟
      const simulation = d3
        .forceSimulation(this.data)
        .force("charge", d3.forceManyBody().strength(0)) // 负值表示引力
        .force("center", d3.forceCenter(this.width / 2, this.height / 2))
        .force("collision", d3.forceCollide().radius(0)) // 根据节点大小调整碰撞半径
        .alphaDecay(0.02) // 设置阻尼
        .velocityDecay(0.4) // 设置速度衰减
        .on("tick", ticked);

      const node = svg
        .selectAll("g")
        .data(this.data)
        .enter()
        .append("g")
        .call(
          d3
            .drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended)
        );

      // 添加圆圈
      node
        .append("circle")
        .attr("r", this.yuan) // 圆的半径根据宽度进行缩放
        .attr("fill", "steelblue")
        .style("cursor", "move"); // 添加拖动时的光标样式
      // 在 createChart 方法中添加以下代码

      // 添加文字
      node
        .append("text")
        .text((d) => d.pathway)
        .attr("x", function (d) {
          console.log(d.x);
          return d.x > 0
            ? Math.random() * 0.04 * component.width + 0.01 * component.width
            : Math.random() * -0.04 * component.width - 0.01 * component.width;
          // 在正负方向上随机分布，x 坐标范围在 [-0.04 * width, 0.04 * width] 之间
        })
        .attr("y", function (d) {
          return d.y > 0
            ? Math.random() * 0.1 * component.height + 0.01 * component.height
            : Math.random() * -0.1 * component.height - 0.01 * component.height;
          // 在正负方向上随机分布，y 坐标范围在 [-0.03 * height, 0.03 * height] 之间
        })
        .style("font-size", `${this.fons}px`); // 设置字体大小为 width 的 1%，根据需要调整大小

      // 添加连线
      const line = node
        .append("line")
        .attr("stroke", "gray")
        .attr("stroke-width", 0.5);

      // 更新连线的位置
      function updateLines() {
        line
          .attr("x1", 0)
          .attr("y1", 0)
          .attr("x2", function (d) {
            const text = d3.select(this.parentNode).select("text");
            return +text.attr("x");
          })
          .attr("y2", function (d) {
            const text = d3.select(this.parentNode).select("text");
            return +text.attr("y");
          });
      }

      function ticked() {
        // 更新圆圈和文字的位置
        node.attr("transform", (d) => `translate(${d.x},${d.y})`);

        // 更新连线的位置
        updateLines();
      }

      function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(event, d) {
        // 限制节点移动范围
        d.fx = Math.max(10, Math.min(event.x, component.width - 10));
        d.fy = Math.max(10, Math.min(event.y, component.height - 10));
      }

      function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      }
    },
  },
};
</script>

<style scoped></style>
